
import * as path from "path";
import { ApiCall, BaseServiceType, HttpConnection, HttpServer, HttpServerOptions } from "tsrpc";
import { serviceProto as hallServiceProto, ServiceType as HallServiceType } from "../shared/hallClient/protocols/serviceProto";
import { IGameServerInfo } from "../shared/hallClient/Models";
import { IRedisClient } from "../shared/tsgfServer/redisHelper";
import { GameServerClusterMgr } from "../gameServerCluster/GameServerClusterMgr";
import { MatchRequestServer } from "../shared/matchRequest/MatchRequestServer";
import { BaseConf } from "../shared/hallClient/protocols/base";
import { IPlayer, IPlayerAuthInfo } from "../shared/tsgfServer/auth/Models";
import { IApiCrypto } from "../shared/tsgfServerEDB/apiCrypto/IApiCrypto";
import { AppCrypto } from "../shared/tsgfServerEDB/apiCrypto/AppCrypto";
import { PlayerAuthHelper } from "../shared/tsgfServer/auth/PlayerAuthHelper";
import { ENetworkState, IPlayerInfo } from "../shared/tsgf/player/IPlayerInfo";
import { ErrorCodes } from "../shared/tsgf/Result";


/**
 * 大厅服务器API专用的ApiCall类型，可用于获取大厅服务对象
 * @date 2022/4/26 - 16:21:57
 *
 * @typedef {HallApiCall}
 * @typeParam req
 * @typeParam res
 */
export type HallApiCall<req, res> = ApiCall<req, res, HallServiceType> & {
    getHallServer: () => HallServer;
};


/**
 * 大厅服务器，可直接部署多台（本服务中的所有功能都是直接支持多台部署），由nginx这样的组件来实现负载均衡。
 * @date 2022/4/26 - 15:06:38
 *
 * @class HallServer
 * @typedef {HallServer}
 */
export class HallServer {
    public server: HttpServer<HallServiceType>;
    private getRedisClient: (reuseClient: boolean) => Promise<IRedisClient>;

    public matchRequestServer: MatchRequestServer;

    /**api加解密实现字典*/
    private apiCryptoImpls: { [key: string]: IApiCrypto } = {
        "AppReqDes": new AppCrypto(),
    };

    constructor(getRedisClient: (reuseClient: boolean) => Promise<IRedisClient>, serverOptions: Partial<HttpServerOptions<HallServiceType>>) {
        this.getRedisClient = getRedisClient;
        this.server = new HttpServer(hallServiceProto, serverOptions);
        this.server.flows.preRecvDataFlow.push(v => {
            let conn = v.conn as HttpConnection;
            //解决HTTP请求跨域问题
            conn.httpRes.setHeader("Access-Control-Allow-Origin", "*");
            return v;
        })
        this.server.flows.preApiCallFlow.push(async (v: HallApiCall<any, any>) => {
            let conf = v.service.conf as BaseConf;
            if (!conf.skipAuth) {
                //接口没定义"不认证",则需要进行身份认证
                if (!v.req.playerToken) {
                    v.error("需要 playerToken !", { code: ErrorCodes.ParamsError });
                    return null;
                }
                let vRet = await PlayerAuthHelper.verification(v.req.playerToken);
                if (!vRet.succ) {
                    v.error(vRet.err, { code: vRet.code });
                    return null;
                }
                let authInfo = vRet.data;
                let playerInfo: IPlayerInfo = {
                    playerId: authInfo.playerId,
                    showName: authInfo.showName,
                    customPlayerStatus: 0,
                    customPlayerProfile: '',
                    isRobot: false,
                    networkState: ENetworkState.ONLINE,
                };

                let player: IPlayer = {
                    authInfo: authInfo,
                    playerInfo: playerInfo
                };
                v.conn.currPlayer = player;
            }
            let apiCryptoImpl = this.apiCryptoImpls[conf.cryptoMode];
            if (apiCryptoImpl) {
                let ret = await apiCryptoImpl.decryptionReq(v.req);
                if (!ret.succ) {
                    v.error(ret.err, { code: ret.code });
                    return null;
                }
            }
            v.getHallServer = () => this;
            return v;
        });

        this.matchRequestServer = new MatchRequestServer(getRedisClient, true);
    }


    /**
     * 启动服务
     *
     * @public
     * @returns
     */
    public async start(): Promise<void> {
        await this.matchRequestServer.start();

        await this.server.autoImplementApi(path.resolve(__dirname, 'api'));
        await this.server.start();
    }
    /**停止服务*/
    public async stop(): Promise<void> {
        await this.server.stop();
        await this.matchRequestServer.stop();
    }

    /**
     * 获取所有在线游戏服务器信息
     *
     * @public
     * @returns
     */
    public async getAllGameServers(): Promise<IGameServerInfo[]> {
        //这里仅作游戏集群管理类的依赖，部署并不依赖
        let nodeList = await GameServerClusterMgr.getServersFromRedis(this.getRedisClient);
        return nodeList.map(n => n.info);
    }
    /**
     * 获取指定的在线游戏服务器信息
     *
     * @public
     * @returns
     */
    public async getGameServer(serverNodeId: string): Promise<IGameServerInfo | null> {
        //这里仅作游戏集群管理类的依赖，部署并不依赖
        let node = await GameServerClusterMgr.getServerInfoFromRedis(serverNodeId, this.getRedisClient);
        return node?.info ?? null;
    }


}